#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>

int check_ip_mail(char *pop3, char *user, char *psw);
void send_ip_mail(char *dest, char *smtp, char *user, char *psw);

int main(int argc, char *argv[])
{
    if (argc != 6) {
        printf("Usage:\n    %s <dest mail> <pop3 server> <smtp server> <user name> <password>\n", argv[0]);
        printf("Example:\n    %s ro@sina.com pop.sina.com smtp.sina.com ro@sina.com 2fd825fd3df9da4a\n", argv[0]);
        return 0;
    }
    for (;;) {
        if (check_ip_mail(argv[2], argv[4], argv[5])) {
            printf("Refresh Subject ip...");
            fflush(stdout);
            send_ip_mail(argv[1], argv[3], argv[4], argv[5]);
        }
        sleep(60);
    }
    return 0;
}

int sendln(int sd, char *s)
{
    printf("<<%s\n", s);
    int len = strlen(s);
    int n, remain = len;
    for (n = 0;remain > 0;remain -= n) {
        n = send(sd, s, remain, 0);
        if (n <=0) return n;
        s += n;
    }
    send(sd, "\r\n", 2, 0);
    return len;
}

char *recvln(int sd, char *s, int size)
{
    char *p = s;

    while (size > 0) {
        if (1 == recv(sd, p, 1, 0)) {
            if (*p == '\n') {
                *p = 0;
                if ((p != s) && (*(p - 1) == '\r')) *(p - 1) = 0;
                break;
            }
            p++;
            size--;
        } else {
            return NULL;
        }
    }
    printf(">>%s\n", s);
    return s;
}

int strcmp2(char *str1, char *str2)
{
    while(*str2) {
        if (*str1 < *str2) return -1;
        if (*str1 > *str2) return 1;
        str1++;
        str2++;
    }
    return 0;
}

int check_ip_mail(char *pop3, char *user, char *psw)
{
    int ret = -1;
    struct hostent * iphost;
    if((iphost = gethostbyname(pop3)) != NULL) {
        int sd = socket(AF_INET, SOCK_STREAM, 0);
        struct sockaddr_in servaddr;
        memset(&servaddr, 0x00, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr = *(struct in_addr *)iphost->h_addr_list[0];
        char s[256];

        servaddr.sin_port = htons(110);
        if (connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) {
            recvln(sd, s, sizeof(s));
            if (strcmp2(s, "+OK")) {
                printf("Error at %d, %s\n", __LINE__, s);
                goto Fail;
            }
            sprintf(s, "user %s", user);
            sendln(sd, s);
            recvln(sd, s, sizeof(s));
            if (strcmp2(s, "+OK")) {
                printf("Error at %d, %s\n", __LINE__, s);
                goto Fail;
            }
            sprintf(s, "pass %s", psw);
            sendln(sd, s);
            recvln(sd, s, sizeof(s));
            if (strcmp2(s, "+OK")) {
                printf("Error at %d, %s\n", __LINE__, s);
                goto Fail;
            }
            int i;
            sscanf(s, "+OK %d messages", &i);
            if (i > 0) {
                sprintf(s, "retr %d", i);
                sendln(sd, s);
                recvln(sd, s, sizeof(s));
                if (strcmp2(s, "+OK")) {
                    printf("Error at %d, %s\n", __LINE__, s);
                    goto Fail;
                }
                for (;;) {
                    recvln(sd, s, sizeof(s));
                    if (!strcmp(s, "Subject: ip")) ret = 0;
                    if (!strcmp(s, ".")) break;
                }
                sendln(sd, "quit");
                goto Close;
            }
Fail:
            sendln(sd, "quit");
        }
Close:
        close(sd);
    }
    return ret;
}

char *base64_encode(char *str, char *dst)  
{  
    long len;  
    long str_len;
    int i,j;  
    char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  

    str_len = strlen(str);  
    if (str_len % 3 == 0)  
        len=str_len/3*4;  
    else  
        len=(str_len/3+1)*4;  

    dst[len] = '\0';  

    for(i = 0,j = 0;i < len - 2;j += 3, i += 4)  
    {  
        dst[i] = base64_table[str[j] >> 2];
        dst[i+1] = base64_table[(str[j] & 0x3) << 4 | (str[j + 1] >> 4)];
        dst[i+2] = base64_table[(str[j + 1] & 0xf) << 2 | (str[j + 2] >> 6)];
        dst[i+3] = base64_table[str[j + 2] & 0x3f];
    }  

    switch(str_len % 3)  
    {  
        case 1:  
            dst[i - 2] = '=';  
            dst[i - 1] = '=';  
            break;  
        case 2:  
            dst[i - 1] = '=';  
            break;  
    }  

    return dst;  
}  


void send_ip_mail(char *dest, char *smtp, char *user, char *psw)
{
    struct hostent * iphost;
    if((iphost = gethostbyname(smtp)) != NULL) {
        int sd = socket(AF_INET, SOCK_STREAM, 0);
        struct sockaddr_in servaddr;
        memset(&servaddr, 0x00, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_addr = *(struct in_addr *)iphost->h_addr_list[0];
        char s[256];

        servaddr.sin_port = htons(25);
        if (connect(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) {
            recvln(sd, s, sizeof(s));
            if (strcmp2(s, "220")) {
                printf("Error at %d, %s\n", __LINE__, s);
                goto Exit;
            }
            sendln(sd, "auth login");
            recvln(sd, s, sizeof(s));
            if (strcmp2(s, "334")) {
                printf("Error at %d, %s\n", __LINE__, s);
                goto Exit;
            }
            sendln(sd, base64_encode(user, s)); 
            recvln(sd, s, sizeof(s));
            if (strcmp2(s, "334")) {
                printf("Error at %d, %s\n", __LINE__, s);
                goto Exit;
            }
            sendln(sd, base64_encode(psw, s));
            recvln(sd, s, sizeof(s));
            if (strcmp2(s, "235")) {
                printf("Error at %d, %s\n", __LINE__, s);
                goto Exit;
            }
            sprintf(s, "mail to:<%s>", dest);
            sendln(sd, s);
            sprintf(s, "rcpt to:<%s>", dest);
            sendln(sd, s);
            sendln(sd, "data");
            sprintf(s, "From:<%s>", user);
            sendln(sd, s);
            sendln(sd, "Subject: ip");
            sendln(sd, "");
            sendln(sd, ".");
            recvln(sd, s, sizeof(s));
            printf ("%s\n", s);
Exit:
            sendln(sd, "quit");
        }
        close(sd);
    }
}
